<?php

namespace App\Library\Service;

use App\Library\Logic\AddressLogic;
use App\Library\Logic\AmountLogic;
use App\Library\Logic\KefuLogic;
use App\Library\Logic\OpenIdLogic;
use App\Library\Logic\OperateLogLogic;
use App\Library\Logic\PaymentLogic;
use App\Library\Logic\PaymentRelatedLogic;
use App\Library\Logic\ProductSpecLogic;
use App\Library\Logic\SalesRecordLogic;
use App\Library\Logic\ShopImagesLogic;
use App\Library\Logic\ShopOrderExtLogic;
use App\Library\Logic\ShopOrderGoodsLogic;
use App\Library\Logic\ShopOrderLogic;
use App\Library\Logic\ShopProductExtLogic;
use App\Library\Logic\ShopProductLogic;
use App\Library\Logic\ShopProductSpecsLogic;
use App\Library\Logic\ShopUserCollectLogic;
use App\Library\Requests\Base\SerialNumberRequest;
use App\Library\Requests\Plug\PlugAddRequest;
use App\Library\Requests\Plug\PlugCreateRequest;
use App\Library\Requests\Plug\PlugPageRequest;
use App\Library\Service\Payment\WechatService;
use App\Library\YsdLib;
use App\Models\OpenIdModel;
use App\Models\ShopProductExtModel;
use App\Models\ShopProductModel;
use App\Models\SystemConfigModel;
use Exception;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Arr;
use Yansongda\Pay\Pay;
use Illuminate\Support\Str;

class PlugService extends BaseService
{
    /**
     * paging
     * @param PlugPageRequest $request
     * @return JsonResponse
     */
    public function paging(PlugPageRequest $request): JsonResponse
    {
        if ($request->version === 2) return $this->paging2($request);
        $builder = ShopProductLogic::query()->with('specPlug')->where('product_status', 2)
            ->where('product_special_start_time', '>', 0)->orderByDesc('status_recommend')->orderBy('sort')->orderBy('product_special_start_time');
        if (is_null($request->plug)) $builder->where('plug2', '>', 0);
        else $builder->where('plug2', (int)$request->plug);
        if (!is_null($request->keyword)) {
            $keyword = htmlspecialchars(strip_tags(trim($request->keyword)));
            if (!empty($keyword)) $builder->where('product_name', 'like', "%$keyword%");
        }
        return success(paginate($builder->paginate($request->limit, $this->colum())));
    }

    public function pList($request)
    {
        return success($this->commonPage($this->pag($request), 1));
    }

    private function commonPage($data, int $type = 0)
    {
        foreach ($data['data'] as &$value) {
            $value->product_special_start_time = $value->product_special_start_time > 0 ? date('Y-m-d H:i:s', $value->product_special_start_time) : 0;
            $value->product_special_end_time = $value->product_special_end_time > 0 ? date('Y-m-d H:i:s', $value->product_special_end_time) : 0;
            $specs = ProductSpecLogic::getSpecsCommissionInfo($value->product_id);

            if (!empty($specs)) {
                $psPrice = array_filter(array_column($specs, 'ps_price'), function ($v) {
                    return $v > 0;
                });
                $underlinePrice = array_filter(array_column($specs, 'ps_price_underlined'), function ($v) {
                    return $v > 0;
                });
                $commission = self::commonCommission([
                    'start_time' => $value->product_special_start_time,
                    'end_time' => $value->product_special_end_time,
                    'specs' => $specs
                ]);
                $value->lower_commission = $commission['lower_commission'];

                if ($type) {
                    $value->discount_price = empty($psPrice) || min($psPrice) >= min($underlinePrice) ? min($underlinePrice) : min($psPrice);
                    $value->normal_price = min($underlinePrice) === max($underlinePrice) ? min($underlinePrice) : min($underlinePrice) . '~' . max($underlinePrice);
                } else {
                    $value->normal_price = $commission['normal_price'];
                    $value->discount_price = empty($psPrice) || min($psPrice) >= min($underlinePrice) ? min($underlinePrice) : min($psPrice);
                }
            } else {
                $value->discount_price = 0;
                $value->normal_price = 0;
            }

        }

        return $data;
    }

    private function commonCommission(array $data): array
    {
        //佣金
        $commissionArr = array_filter(array_column($data['specs'], 'commission'), function ($v) {
            return $v > 0;
        });
        //优惠价*比例后的佣金
        $commissionRatioArr = array_filter(array_column($data['specs'], 'commission_ratio'), function ($v) {
            return $v > 0;
        });
        //原价*比例后的佣金
        $underlineCommissionRatioArr = array_filter(array_column($data['specs'], 'underline_commission_ratio'), function ($v) {
            return $v > 0;
        });

        $now = now()->toDateTimeString();
        if ($data['start_time'] <= $now && $data['end_time'] > $now) {
            if (empty($commissionArr) && empty($commissionRatioArr)) $arr['lower_commission'] = 0;
            else if (!empty($commissionArr) && empty($commissionRatioArr)) $arr['lower_commission'] = min($commissionArr);
            else if (empty($commissionArr) && !empty($commissionRatioArr)) $arr['lower_commission'] = min($commissionRatioArr);
            else $arr['lower_commission'] = min($commissionArr) <= min($commissionRatioArr) ? min($commissionArr) : min($commissionRatioArr);

            usort($data['specs'], function ($a, $b) {
                if ($a['ps_price'] == $b['ps_price']) {
                    return 0;
                }
                return ($a['ps_price'] < $b['ps_price']) ? -1 : 1;
            });
        } else {
            if (empty($commissionArr) && empty($underlineCommissionRatioArr)) $arr['lower_commission'] = 0;
            else if (!empty($commissionArr) && empty($underlineCommissionRatioArr)) $arr['lower_commission'] = min($commissionArr);
            else if (empty($commissionArr) && !empty($underlineCommissionRatioArr)) $arr['lower_commission'] = min($underlineCommissionRatioArr);
            else $arr['lower_commission'] = min($commissionArr) <= min($underlineCommissionRatioArr) ? min($commissionArr) : min($underlineCommissionRatioArr);
            usort($data['specs'], function ($a, $b) {
                if ($a['ps_price_underlined'] == $b['ps_price_underlined']) {
                    return 0;
                }
                return ($a['ps_price_underlined'] < $b['ps_price_underlined']) ? -1 : 1;
            });
        }
        $arr['normal_price'] = $data['specs'][0]['ps_price_underlined'] ?? null;
        return $arr;
    }

    private function pag($request): array
    {
        $builder = ShopProductLogic::query()
            ->leftJoin('shop_product_ext as b','b.product_id','=','shop_product.product_id')
            ->where([
                'plug2'=>1
            ])->with(['categoryOne', 'categoryTwo', 'categoryThree']);
        if ($request->status === 0 || is_null($request->status)) $builder->where('product_status', 2)->orderBy('publish_at', $request->orderBy);
        else if ($request->status === 1) $builder->where('product_status', 1)->orderBy('created_time', $request->orderBy);
        else if ($request->status === 2) $builder->whereIn('product_stock_empty', [2, 3])->orderByDesc('created_at');

        if (MAINID !== config('superId') && is_null($request->header('newAuth'))) {
            if (USERID === MAINID || POWER === 1) $builder->where('shop_product.user_id', MAINID);
            else $builder->where('add_user_id', USERID);
        }

        if (!is_null($request->startAt)) {
            $builder->whereBetween('shop_product.created_at', [
                strtotime(now()->parse($request->startAt)->startOfDay()->format('Y-m-d H:i:s')),
                strtotime(now()->parse($request->endAt)->endOfDay()->format('Y-m-d H:i:s'))
            ]);
        }
        if (!is_null($request->keyword)) $builder->where('product_name', 'LIKE', '%' . $request->keyword . '%');

        return paginate($builder->paginate($request->limit, [
            'serial_number',
            'shop_product.product_id',
            'product_special_start_time',
            'product_special_end_time',
            'product_avatar',
            'product_name',
            'product_status',
            'product_stock_empty',
            'product_category_id_1',
            'product_category_id_2',
            'product_category_id_3',
            'created_time',
            'publish_at',
            'add_at',
            'shelf_day',
            'plug_hour',
            'plug_num',
            'plug_cate',
            'max_price',
            'min_price'
        ]));
    }
    private function paging2(PlugPageRequest $request): JsonResponse
    {
        $builder = ShopProductLogic::query()->leftJoin('shop_product_ext', 'shop_product_ext.product_id', 'shop_product.product_id')
            ->where('product_status', 2)->where('plug2', 1)
            ->where('product_special_start_time', '>', 0)->orderByDesc('status_recommend')->orderBy('sort')
            ->orderBy('product_special_start_time')->orderBy('min_price');
        if (!is_null($request->plug)) $builder->where('plug_cate', $request->plug);
        if (!is_null($request->keyword)) {
            $keyword = htmlspecialchars(strip_tags(trim($request->keyword)));
            if (!empty($keyword)) $builder->where('product_name', 'like', "%$keyword%");
        }
        $paginate = $builder->paginate($request->limit, $this->colum2());
        foreach ($paginate->items() as $v) {
            $v->second = ShopProductLogic::reduce($v->product_special_start_time, $v->plug_hour);
            unsetObject($v, ['plug_hour', 'product_special_start_time']);
        }
        return success(paginate($paginate));
    }

    /**
     * create
     * @param PlugCreateRequest $request
     * @return JsonResponse
     * @throws Exception|GuzzleException
     */
    public function create(PlugCreateRequest $request): JsonResponse
    {
        $address = AddressLogic::detail($request->addressId);
        if (is_null($address) || $address->user_id !== USERID) return fail(422);
        //$spec = ShopProductSpecsLogic::detail((int)cache('shopProductSpec:' . $request->serialNumber));
        $spec = ShopProductSpecsLogic::query()->where('serial_number',$request->serialNumber)->first();
        if (is_null($spec)) return fail(422);
        $product = ShopProductLogic::detail($spec->product_id);
        if (is_null($product)) return fail(422);
        else if ($product->product_status !== 2) return failMessage('商品已下架');
        else if ($product->product_stock_empty !== 1) return failMessage('库存不足');
        else if ($spec->ps_total_stock !== 1) return failMessage('库存不足');

        if ($request->version === 2) {
            $price = $product->min_price;
            if (ShopUserCollectLogic::isFollow($product->product_id)) {
                if (OpenIdLogic::isFollow()) $price -= 5;
                if ($price <= 0) $price = 0.01;
            }
        } else {
            if ($spec->ps_price * 1 <= 0) return fail(422);
            else if ($product->plug2 === 0 || $product->product_special_start_time === 0) return fail(422);
            else if ($request->plug2 === true && time() < $product->product_special_start_time) {
                return failMessage('未到捡漏时间,请稍后再试');
            }
            $price = $request->plug2 === true ? $spec->ps_price : $spec->ps_price_underlined;
        }
        if (is_null($request->code) && AmountLogic::balance() < $price) return failMessage('余额不足');
        $order = ShopOrderLogic::insertForModel([
            'plug' => 0,
            'buyUserId' => USERID,
            'sellUserId' => $product->user_id,
            'payPrice' => $price,
            'orderTotalPrice' => $price,
            'orderTotalRealPrice' => $price,
            'orderContacts' => $address->contacts,
            'orderContactsMobile' => $address->mobile,
            'orderContactsAddress' => $address->full_address,
            'orderAddTime' => time(),
            'orderNote' => $request->remark,
            'plug2' => 1,
        ]);
        mq('productOrderCancel', $order->serial_number, (int)__('base.plugCancelTtl'));
        ShopOrderExtLogic::add($order, 0, $address->id);
        ShopOrderGoodsLogic::plug($product, $spec, $order);
        ProductSpecLogic::decStock([[
            'quantity' => 1,
            'specId' => $spec->ps_id,
            'productId' => $product->product_id,
            'psUsableStock' => $spec->ps_usable_stock
        ]]);
        $paymentMethodId = is_null($request->code) ? 4 : 2;
        $paymentRelated = PaymentRelatedLogic::addByProductOrder($order, $paymentMethodId);
        if ($paymentMethodId === 2) {
            Pay::config(YsdLib::config());
            $order->title = '异宠星球';
            return WechatService::mini($order, $paymentRelated->serial_number, $request->code);
        }
        PaymentLogic::plug($order, $product, AmountLogic::plug($order), $paymentRelated, $paymentMethodId);
        ShopOrderLogic::paySuccess($order->order_id, now()->toDateTimeString());
        ShopProductLogic::saveSale($order->order_id);
        SalesRecordLogic::addOrEditOfShopOrder($order);
        return success(['payPrice' => $order->pay_price, 'serialNumber' => $order->serial_number]);
    }

    /**
     * list
     * @return JsonResponse
     */
    public function list(): JsonResponse
    {
        $list = ShopOrderLogic::query()->leftJoin('shop_order_ext', 'shop_order_ext.order_id', 'shop_order.order_id')
            ->leftJoin('address', 'address.id', 'shop_order_ext.address_id')->where([
                'shop_order.plug' => 1,
                'shop_order_ext.status_pay' => 1,
                ['shop_order_ext.address_id', '>', 0],
            ])->orderByDesc('pay_at')->limit(30)->get([
                'shop_order_ext.user_id',
                'shop_order_ext.extend',
                'shop_order.order_contacts_mobile as mobile',
                'address.province',
                'address.city',
                'address.district',
            ]);
        foreach ($list as $v) {

            /*if ($v->user_id === config('app.plugId')) {
                if (!is_null($v->extend)) {
                    $v->mobile = Arr::get(json_decode($v->extend, true), 'plug.mobile');
                    $v->address = Arr::get(json_decode($v->extend, true), 'plug.address');
                }
            } else
                $v->address = $v->province . $v->city . $v->district;
            $v->mobile = substr_replace($v->mobile, '****', 3, 4);*/
            $v->nickname = '';
            if (!is_null($v->extend)) {
                $v->nickname = Arr::get(json_decode($v->extend, true), 'plug.nickname');
            }
            $v->address = $v->province;
            $v->mobile = Str::substr($v->mobile, -4);
            unsetObject($v, ['province', 'city', 'district', 'user_id']);
        }
        return success($list);
    }

    public function add(PlugAddRequest $request)
    {
        $imgIds = '';
        if (is_null($request->main_img_ids)) {
            $request->main_img_ids = ["00000000000000000000"];
            $request->product_avatar = __('com.defaultImg');
        } else {
            $imgIds = $request->main_img_ids;
            $request->product_avatar = $request->main_img_ids[0];
        }
        $proData = [
            'serial_number' => ShopProductLogic::getSerialNumber(),
            'userId' => MAINID,
            'addUserId' => USERID,
            'product_status' => 2,
            'product_name' => $request->product_name,
            'product_category_id_1' => 1,
            'product_category_id_2' => [0, 37, 32, 41][$request->plug_cate],
            'product_category_id_3' => [0, 39, 43, 42][$request->plug_cate],
            'main_img_ids' => $request->main_img_ids,
            'product_avatar' => $request->product_avatar,
            'product_stage' => $request->product_stage ?? 0,
            'product_gene' => $request->product_gene ?? null,
            'product_label' => $request->product_label ?? null,
            'product_special_start_time' => $request->product_special_start_time ?? 0,
            'product_note' => $request->product_note ?? null,
            'product_content' => $request->product_content ?? null,
            'min_price' => $request->max_price ?? 0,
            'max_price' => $request->max_price ?? 0,
            'desc_img_ids' => $request->desc_img_ids ?? null,
            'video_id' => $request->video_id ?? null,
            'publish_at' => now()->toDateString(),
            'created_time' => now()->toDateString(),
            'product_status' => $request->product_status,
            'plug2' => 1,
        ];

        $proModel = ShopProductLogic::insertForModel($proData);
        $proArr = null;
        $deArr = null;
        if (!empty($imgIds)) {
            $proArr = ShopImagesLogic::imgIds(4, $imgIds, $proModel->product_id);
        }
        if (!empty($request->desc_img_ids))
            $deArr = ShopImagesLogic::imgIds(5, $request->desc_img_ids, $proModel->product_id);
        $proModel->product_avatar_img_id_json = !empty($proArr) ? json_encode($proArr) : null;
        $proModel->product_content_img_id_json = !empty($deArr) ? json_encode($deArr) : null;
        if (!empty($proArr) || !empty($deArr)) {
            $proModel->save();
        }
        $proExtData = [
            'product_id' => $proModel->product_id,
            'shelf_day' => $request->shelf_day,
            'plug_hour' => $request->plug_hour,
            'plug_num' => $request->plug_num,
            'plug_cate' => $request->plug_cate,
        ];
        ShopProductExtLogic::insertForModel($proExtData);
        $spec = ShopProductSpecsLogic::insertForModel([
            'productId' => $proModel->product_id,
            'randProductId' => 0,
            'userId' => USERID,
            'psPrice' => $proData['min_price'],
            'psPriceUnderlined' => $proData['min_price'],
            'psTotalStock' => 1,
            'psUsableStock' => 1,
            'psName' => '默认',
        ]);
        mq('shopProductChange', $proModel);
        OperateLogLogic::add();
        return success();
    }


    /**
     * edit
     * @param PlugAddRequest $request
     * @return JsonResponse
     * @throws Exception
     */
    public function edit(PlugAddRequest $request): JsonResponse
    {
        $arr = $request->all();
        $model = ShopProductModel::query()
            ->where([
                'serial_number' => $request->serial_number,
                'product_is_delete' => 2
            ])->first();
        if (empty($model)) return failMessage('无商品信息');
        foreach ($arr as $k => $v) {
            if (!isset($model->$k)) continue;
            $model->$k = $v;
            if ($k === 'main_img_ids') {
                $proArr = null;
                if (!empty($v) && $v[0] !== "00000000000000000000") {
                    $proArr = ShopImagesLogic::imgIds(4, $v, $model->product_id);
                } else {
                    $model->main_img_ids = ["00000000000000000000"];
                }
                $model->product_avatar_img_id_json = !empty($proArr) ? json_encode($proArr) : null;
            }
            if ($k === 'desc_img_ids') {
                $deArr = null;
                if (!empty($v)) {
                    $deArr = ShopImagesLogic::imgIds(5, $v, $model->product_id);
                }
                $model->product_content_img_id_json = !empty($deArr) ? json_encode($deArr) : null;
            }

            if ($k === 'max_price') {
                $model->max_price = $v;
                $model->min_price = $v;
            }
            if ($k === 'plug_cate') {
                $model->plug02 = $v;
            }
        }
        $model->edit_user_id = USERID;
        $model->save();
        $extModel = ShopProductExtModel::query()
            ->where('product_id', $model->product_id)->first();
        if (!empty($extModel)) {
            foreach ($arr as $ek => $ev) {
                if (!isset($extModel->$ek)) continue;
                $extModel->$ek = $ev;
            }
            $extModel->save();
        }
        mq('shopProductChange', $model);
        OperateLogLogic::add();
        return success();
    }

    public function del(SerialNumberRequest $request)
    {
        $item = $this->checkItem($request->serialNumber);
        if ($item instanceof JsonResponse) return $item;
        else if ($item->product_status === 2) return failMessage('已上架商品无法删除');
        $item->deleted_at = now();
        $item->product_is_delete = 1;
        $item->save();
        OperateLogLogic::add();
        return success();
    }
    /**
     * 详情
     * @return JsonResponse
     *
     */
    public function detail($request): JsonResponse
    {
        $model = ShopProductLogic::detail($request->id);
        if (is_null($model)) return fail(433);
        $userId = userId();
        if ($model->is_agent && !cache()->has('agent:' . $userId)) return fail(422);
        $specs = ProductSpecLogic::getSpecsCommissionInfo($model->product_id);
        $commission = self::commonCommission([
            'start_time' => date('Y-m-d H:i:s', $model->product_special_start_time),
            'end_time' => date('Y-m-d H:i:s', $model->product_special_end_time),
            'specs' => $specs
        ]);
        //添加点击
        $model->product_hits += 1;
        $model->save();
        $model->lower_commission = $commission['lower_commission'];
        $model->normal_price = $commission['normal_price'];
        $model->specs;
        $model->collect = ShopUserCollectLogic::existsByWhere([
            'ucType' => 1,
            'userId' => $userId,
            'ucSourceId' => $model->product_id
        ]);
        $model->isFollow = OpenIdLogic::existsByWhere([
            'userId' => $userId,
            'plateform' => 2,
            'type' => 'wx',
            'isFollow' => 1
        ]);
        $model->is_kefu = $userId > 0 && $model->user_id === KefuLogic::isKeFu($userId);
        if ($model->plug2 === 1) {
            $model->second = ShopProductLogic::reduce($model->product_special_start_time, $model->ext->plug_hour);
            unsetObject($model, ['ext']);
            $extInfo = ShopProductExtLogic::query()
                ->where('product_id',$model->product_id)->first();
            $model->shelf_day =$extInfo->shelf_day;
            $model->plug_hour =$extInfo->plug_hour;
            $model->plug_num =$extInfo->plug_num;
            $model->plug_cate =$extInfo->plug_cate;
            $model->help_price =$extInfo->help_price;
        }
        return success($model);
    }
    public function upOrDown($request)
    {
        $item = $this->checkItem($request->serialNumber);
        if ($item instanceof JsonResponse) return $item;
        if ($item->product_status == 2) {
            if (now()->timestamp < $item['product_special_start_time'] && $request->status == 1)
                return failMessage('商品活动已经开始，不能下架');
        }
        $item->updated_at = now();
        $item->product_status = $request->status;
        $item->save();
        OperateLogLogic::add();
        return success();
    }

    /**
     * checkItem
     * @param string $serialNumber
     * @return Model|JsonResponse
     */
    private function checkItem(string $serialNumber): Model|JsonResponse
    {
        $item = ShopProductLogic::findBySerialNumber($serialNumber);
        if (is_null($item)) return fail(433);
        /* else if (USERID === MAINID || POWER === 1) {
             if ($item->user_id !== MAINID) return fail(433);
         } else if ($item->user_id !== USERID) return fail(433);*/
        return $item;
    }

    private function colum(): array
    {
        return [
            'product_id', 'product_name', 'serial_number', 'product_avatar', 'product_special_start_time',
            'product_stock_empty','min_price'
        ];
    }

    private function colum2(): array
    {
        return [
            'shop_product.product_id', 'product_name', 'serial_number', 'product_avatar', 'product_special_start_time',
            'product_stock_empty', 'min_price', 'plug_hour',
        ];
    }
}
